﻿using DLC.Module.DataTable.ArchiveBytes;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using UnityEngine;
namespace DLC.Module.DataTable.ArchiveBytes
{
    public static partial class DataTableBytesExtension
    {
        public const string NamespaceGameDataTableArchiveBytes = "DLC.Game.DataTable.ArchiveBytes";

        private delegate void ObjectBinaryWrite(BinaryWriter writer, object data);
        private static Dictionary<Type, ObjectBinaryWrite> _typeToWriteActions = new Dictionary<Type, ObjectBinaryWrite>();
        private delegate object ObjectBinaryRead(BinaryReader reader);
        private static Dictionary<Type, ObjectBinaryRead> _typeToReadActions = new Dictionary<Type, ObjectBinaryRead>();

        static DataTableBytesExtension()
        {
            MethodInfo[] methods = typeof(DataTableBytesExtension).GetMethods();
            for(int i = 0; i < methods.Length; i++)
            {
                var attr = methods[i].GetCustomAttribute<BinaryWriterHelperAttribute>();
                if (attr != null)
                {
                    _typeToWriteActions.Add(attr.Type, (ObjectBinaryWrite)methods[i].CreateDelegate(typeof(ObjectBinaryWrite)));
                }
                var readerAttr = methods[i].GetCustomAttribute<BinaryReaderHelperAttribute>();
                if (readerAttr != null)
                {
                    _typeToReadActions.Add(readerAttr.Type, (ObjectBinaryRead)methods[i].CreateDelegate(typeof(ObjectBinaryRead)));
                }
            }
        }
        public static void Write(this BinaryWriter binaryWriter, object data)
        {
            ObjectBinaryWrite action;
            if (data.GetType().IsEnum)
            {
                _typeToWriteActions.TryGetValue(typeof(Enum), out action);
            }
            else
            {
                _typeToWriteActions.TryGetValue(data.GetType(), out action);
            }
            if (action != null)
            {
                action.Invoke(binaryWriter, data);
            }
        }
        public static object Read(this BinaryReader reader, Type t)
        {
            ObjectBinaryRead action;
            if (t.IsEnum)
            {
                _typeToReadActions.TryGetValue(typeof(Enum), out action);
            }
            else
            {
                _typeToReadActions.TryGetValue(t, out action);
            }
            if (action != null)
            {
                var data = action.Invoke(reader);
                if (t.IsEnum)
                {
                    return Enum.Parse(t, (string)data);
                }
                return data;
            }
            return null;
        }

        public static IDataTableRowType CreateDataTable(this IDataTableManager dataTableManager, string dataTableClassName, byte[] data)
        {
            //var type = DataTableUtil.GetDataTableType(dataTableClassName);
            string className = $"{NamespaceGameDataTableArchiveBytes}.{dataTableClassName}";
            var type = Type.GetType(className);
            if (type != null)
            {
                try
                {
                    var dataTable = Activator.CreateInstance(type);
                    (dataTable as IDataTableBytes).ParseFromBytes(data);
                    dataTableManager.AddDataTable(dataTableClassName, dataTable as IDataTableRowType);
                    return dataTable as IDataTableRowType;
                }
                catch (Exception e)
                {
                    Debug.LogError($"CreateDataTable Error.{e.Message}");
                }
            }
            return null;
        }
    }
}
